/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.phoenix.repository.iterator;

import java.sql.SQLException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Vector;

import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.RepositoryException;

import net.phoenix.repository.JdbcSession;
import net.phoenix.repository.RepositoryRuntimeException;
import net.phoenix.repository.dao.ReferenceValueDao;
import net.phoenix.repository.data.NodePropertyData;

/**
 * 
 * Jigsaw server
 * 
 * @author <a href="shamphone@gmail.com">Li XiongFeng</a>
 * @date 2012-1-3
 * @version 1.0.0
 */
public class NamedReferencePropertyIterator implements PropertyIterator {
	private int pageSize;
	private long size;
	private Iterator<Property> nodes;
	private int position;
	private String name;
	private JdbcSession session;
	private String nodeId;

	public NamedReferencePropertyIterator(JdbcSession session, String nodeId,
			String name) {
		this.session = session;
		this.nodeId = nodeId;
		this.pageSize = 20;
		this.size = -1;
		this.nodes = null;
		this.position = 0;
		this.name = name;
	}

	/**
	 * getSize
	 * 
	 * @return long
	 */
	@Override
	public long getSize() {
		if (this.size >= 0)
			return this.size;
		ReferenceValueDao dao = session.getDao(ReferenceValueDao.class);
		try {
			size = dao.countReferenceByNode(nodeId);
		} catch (SQLException e) {
			throw new RepositoryRuntimeException(e);
		}

		return this.size;

	}

	/**
	 * Returns <tt>true</tt> if the iteration has more elements.
	 * 
	 * @return <tt>true</tt> if the iterator has more elements.
	 */
	@Override
	public boolean hasNext() {
		return this.position < this.getSize();
	}

	@Override
	public void remove() {
		throw new UnsupportedOperationException();
	}

	@Override
	public Property nextProperty() {
		if ((this.nodes == null) || (!this.nodes.hasNext()))
			try {
				this.populateNodes();
			} catch (RepositoryException e) {
				throw new RepositoryRuntimeException(e);
			}
		this.position++;
		return (Property) this.nodes.next();

	}

	private Iterator<Property> populateNodes() throws RepositoryException {
		ReferenceValueDao dao = (ReferenceValueDao) session
				.getDao(ReferenceValueDao.class);
		NodePropertyData[] data;
		Collection<Property> nodes = new Vector<Property>((int) pageSize);
		try {
			data = dao.findReferenceByNode(nodeId, name, position, pageSize);
		} catch (SQLException e) {
			throw new RepositoryException(e);
		}
		for (int i = 0; i < data.length; i++) {
			Node node = session.getNodeByIdentifier(data[i].getID());
			nodes.add(node.getProperty(data[i].getName()));
		}
		NamedReferencePropertyIterator.this.nodes = nodes.iterator();
		return this.nodes;

	}

	protected NodePropertyData[] loadMore(final int fromIndex,
			final int pageSize) throws RepositoryException {
		ReferenceValueDao dao = (ReferenceValueDao) session
				.getDao(ReferenceValueDao.class);
		try {
			return dao.findReferenceByNode(nodeId, name, fromIndex, pageSize);
		} catch (SQLException e) {
			throw new RepositoryException(e);
		}

	}

	@Override
	public void skip(long skipNum) {
		this.position += skipNum;
	}

	@Override
	public long getPosition() {
		return this.position;
	}

	@Override
	public Property next() {
		return this.nextProperty();
	}

}